"""
Library of aggregators useful when grouping table elements.

@author: Christophe Alexandre <optimacom.sarl at gmail dot com>

@license:
Copyright(C) 2010 Optimacom sarl

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/lgpl.txt>.
"""

def agg_sum():
  """
  Aggregate: None-tolerant version of sum().
  
  Use case:
  d = { '0': agg_sum() }
  """
  def f_sum(vector):
    return sum(filter(lambda v: v != None, vector))
  return f_sum

def agg_count():
  """
  Aggregate: None-tolerant version of len().
  
  Use case:
  d = { '0': agg_count() }
  """
  def f_count(vector):
    return len(filter(lambda v: v != None, vector))
  return f_count
  
def agg_avg():
  """
  Aggregate: computing average value.
  
  Use case:
  d = { '0': agg_avg() }
  """
  def f_avg(vector):
    if agg_count()(vector) != 0:
      return agg_sum()(vector) / agg_count()(vector)
    else:
      return None
  return f_avg

def agg_const(c):
  """
  Aggregate: constant c.
  
  Use case:
  d = { '0': agg_const(3) }
  """
  def f_const(vector):
    return c
  return f_const
  
def agg_min():
  """
  Aggregate: finds minimum.
  
  Use case:
  d = { '0': agg_min() }
  """
  def f_min(vector):
    none_safe = filter(lambda x: x is not None, vector)
    return min(none_safe)
  return f_min
  
def agg_max():
  """
  Aggregate: finds maximum.
    
  Use case:
  d = { '0': agg_max() }
  """
  def f_max(vector):
    none_safe = filter(lambda x: x is not None, vector)
    return max(none_safe)
  return f_max
  